using System;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.SceneManagement;

namespace AddressablesTool
{
    /// <summary>
    /// Addressables场景管理器，负责处理场景的异步加载、卸载和管理
    /// </summary>
    public class SceneLoader
    {
        /// <summary>
        /// 已加载场景的句柄字典，键为场景地址
        /// </summary>
        private Dictionary<string, AsyncOperationHandle> _loadedScenes = new Dictionary<string, AsyncOperationHandle>();

        /// <summary>
        /// 是否已初始化完成
        /// </summary>
        private bool _isInitialized;

        /// <summary>
        /// 场景加载开始事件
        /// </summary>
        public event Action<string> OnSceneLoadStart;

        /// <summary>
        /// 场景加载完成事件
        /// </summary>
        public event Action<string> OnSceneLoadComplete;

        /// <summary>
        /// 场景卸载完成事件
        /// </summary>
        public event Action<string> OnSceneUnloaded;

        /// <summary>
        /// 场景加载进度事件
        /// </summary>
        public event Action<string, float> OnSceneLoadProgress;

        /// <summary>
        /// 当前激活的场景地址
        /// </summary>
        public string ActiveSceneAddress { get; private set; }

        /// <summary>
        /// 初始化场景管理器
        /// </summary>
        public void Initialize()
        {
            if (_isInitialized)
                return;
            _isInitialized = true;
        }

        /// <summary>
        /// 异步加载场景
        /// </summary>
        /// <param name="sceneAddress">场景地址</param>
        /// <param name="loadMode">加载模式</param>
        /// <param name="activateOnLoad">是否在加载后激活场景</param>
        /// <returns>加载任务</returns>
        /// <exception cref="InvalidOperationException">未初始化时抛出</exception>
        /// <exception cref="ArgumentException">场景地址为空时抛出</exception>
        /// <exception cref="Exception">加载失败时抛出</exception>
        public async UniTask LoadSceneAsync(string sceneAddress, LoadSceneMode loadMode = LoadSceneMode.Single, bool activateOnLoad = true)
        {
            if (!_isInitialized)
                throw new InvalidOperationException("SceneManager is not initialized. Call Initialize() first");

            if (string.IsNullOrWhiteSpace(sceneAddress))
                throw new ArgumentException("Scene address cannot be null or empty", nameof(sceneAddress));

            if (IsSceneActuallyLoaded(sceneAddress))
            {
                Debug.LogError($"Scene address '{sceneAddress}' already loaded");
                return;
            }

            var handle = Addressables.LoadSceneAsync(sceneAddress, loadMode, activateOnLoad);
            OnSceneLoadStart?.Invoke(sceneAddress);

            while (!handle.IsDone)
            {
                OnSceneLoadProgress?.Invoke(sceneAddress, handle.PercentComplete);
                await UniTask.Yield();
            }

            if (handle.Status != AsyncOperationStatus.Succeeded)
                throw new Exception($"Failed to load scene '{sceneAddress}'. Status: {handle.Status}");

            _loadedScenes[sceneAddress] = handle;
            OnSceneLoadProgress?.Invoke(sceneAddress, 1f);
            OnSceneLoadComplete?.Invoke(sceneAddress);

            if (activateOnLoad)
                ActiveSceneAddress = sceneAddress;
        }

        /// <summary>
        /// 异步卸载场景
        /// </summary>
        /// <param name="sceneAddress">场景地址</param>
        /// <returns>卸载任务</returns>
        /// <exception cref="InvalidOperationException">未初始化时抛出</exception>
        /// <exception cref="ArgumentException">场景未加载或地址为空时抛出</exception>
        /// <exception cref="Exception">卸载失败时抛出</exception>
        public async UniTask UnloadSceneAsync(string sceneAddress)
        {
            if (!_isInitialized)
                throw new InvalidOperationException("SceneManager is not initialized. Call Initialize() first");
            
            if (string.IsNullOrWhiteSpace(sceneAddress))
                throw new ArgumentException("Scene address cannot be null or empty", nameof(sceneAddress));

            if (!_loadedScenes.TryGetValue(sceneAddress, out var loadHandle) || !loadHandle.IsValid())
                throw new ArgumentException($"Scene '{sceneAddress}' is not loaded or handle is invalid", nameof(sceneAddress));

            var unloadHandle = Addressables.UnloadSceneAsync(loadHandle);
            await unloadHandle.Task;

            if (unloadHandle.Status != AsyncOperationStatus.Succeeded)
                throw new Exception($"Failed to unload scene '{sceneAddress}'. Status: {unloadHandle.Status}");

            _loadedScenes.Remove(sceneAddress);
            if (ActiveSceneAddress == sceneAddress)
                ActiveSceneAddress = null;

            OnSceneUnloaded?.Invoke(sceneAddress);
        }

        /// <summary>
        /// 检查指定场景是否已加载
        /// </summary>
        /// <param name="sceneAddress">场景地址</param>
        /// <returns>是否已加载</returns>
        public bool IsSceneLoaded(string sceneAddress)
        {
            return _loadedScenes.ContainsKey(sceneAddress) && _loadedScenes[sceneAddress].IsValid() && _loadedScenes[sceneAddress].IsDone;
        }

        /// <summary>
        /// 检查场景是否真正在Unity中加载（不仅仅是记录在字典中）
        /// </summary>
        /// <param name="sceneAddress">场景地址</param>
        /// <returns>是否真正加载</returns>
        public bool IsSceneActuallyLoaded(string sceneAddress)
        {
            string sceneName = GetSceneNameFromAddress(sceneAddress);
            Scene scene = SceneManager.GetSceneByName(sceneName);

            bool isActuallyLoaded = scene.IsValid() && scene.isLoaded;
            // 如果Unity中已加载，但管理器没记录，说明状态不一致
            if (isActuallyLoaded && !_loadedScenes.ContainsKey(sceneAddress))
            {
                Debug.LogWarning($"Scene '{sceneAddress}' is loaded in Unity but not recorded in manager");
            }

            return isActuallyLoaded;
        }

        /// <summary>
        /// 释放所有已加载的场景
        /// </summary>
        public void ReleaseAllScenes()
        {
            foreach (var handle in _loadedScenes.Values)
            {
                if (handle.IsValid())
                {
                    Addressables.UnloadSceneAsync(handle);
                }
            }

            _loadedScenes.Clear();
        }

        /// <summary>
        /// 从场景地址获取场景名称
        /// </summary>
        /// <param name="sceneAddress">场景地址</param>
        /// <returns>场景名称</returns>
        private string GetSceneNameFromAddress(string sceneAddress)
        {
            var fileName = System.IO.Path.GetFileNameWithoutExtension(sceneAddress);
            return fileName;
        }
    }
}